# -*- -*- -*- -*- -*- -*- -*-
# @Author  : mengzhe
# @Time    : 2025/5/26 11:19
# @File    : client.py
# @function:
# @input   :
# @output  :
# @Software: PyCharm 
# -*- -*- -*- -*- -*- -*- -*-
import socket
import time
from datetime import datetime, timedelta
import threading
from plc import PLC
from weather_station import WEATHER
from radar import ASSRRadarServer

HOST = 'localhost'  # 主服务器地址
PORT = 12345  # 主服务器端口
RADAR_HOST = '192.168.1.135'  # 雷达IP
RADAR_PORT = 3000  # 雷达端口


class ClientConnection:
    def __init__(self):
        self.lock = threading.Lock()
        self.active = False
        self.sock = None  # 主服务器socket
        self.radar_sock = None  # 雷达socket
        self.reconnect_flag = False
        self.last_plc_minute = -1
        self.last_weather_minute = -1
        self.last_time_minute = -1
        self.last_radar_minute = -1
        self.message_counter = 0
        self.counter_lock = threading.Lock()

        # 初始化传感器
        self.plc = PLC(sensor_id="PLC001", name="Industrial_PLC")
        self.weather = WEATHER(sensor_id="WS001", name="Weather_Station")
        self.radar = ASSRRadarServer(host=RADAR_HOST, port=RADAR_PORT)
        self.last_sensor_minute = -1

    def get_next_counter(self):
        with self.counter_lock:
            self.message_counter += 1
            return self.message_counter

    # def connect_to_radar(self):
    #     """持续请求连接雷达设备"""
    #     while self.active:
    #         try:
    #             self.radar_sock = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
    #             self.radar_sock.connect((RADAR_HOST, RADAR_PORT))
    #             print("[Radar] Connected to radar successfully")
    #             return True
    #         except Exception as e:
    #             print(f"[Radar] Connection failed: {str(e)}, retrying...")
    #             time.sleep(5)
    #     return False
    def connect_to_radar(self):
        """连接雷达设备，最多尝试10次"""
        max_retries = 1
        retry_count = 0

        while retry_count < max_retries and self.active:
            try:
                self.radar_sock = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
                self.radar_sock.connect((RADAR_HOST, RADAR_PORT))
                print("[Radar] Connected to radar successfully")
                return True
            except Exception as e:
                retry_count += 1
                remaining = max_retries - retry_count
                print(
                    f"[Radar] Connection failed ({retry_count}/{max_retries}): {str(e)}, retrying in 5s... ({remaining} attempts left)")
                time.sleep(5)

        print("[Radar] Max retries reached, connection abandoned")
        return False

    def process_command(self, cmd):
        """处理来自主服务器的命令"""
        # 处理PLC相关命令
        if cmd.startswith("PLC_"):
            command = cmd[4:]
            if command == "READ":
                return f"[PLC_DATA] {self.plc.read_data()}"
            elif command == "CONFIG":
                return f"[PLC_CONFIG] {self.plc.configure()}"
            elif command == "RESET":
                return f"[PLC_STATUS] {self.plc.reset()}"

        # 处理气象站相关命令
        elif cmd.startswith("WS_"):
            command = cmd[3:]
            if command == "READ":
                return f"[WS_DATA] {self.weather.read_data()}"
            elif command == "CONFIG":
                return f"[WS_CONFIG] {self.weather.configure()}"
            elif command == "RESET":
                return f"[WS_STATUS] {self.weather.reset()}"

        # 处理雷达相关命令
        elif cmd.startswith("RADAR_"):
            command = cmd[6:]
            try:
                with self.lock:
                    if not self.radar_sock:
                        return "[RADAR_ERROR] Not connected to radar"

                    # 发送命令到雷达
                    self.radar_sock.sendall(command.encode())

                    # 等待雷达响应
                    response = self.radar_sock.recv(1024)
                    return f"[RADAR_RESPONSE] {response.decode()}"
            except Exception as e:
                return f"[RADAR_ERROR] {str(e)}"

        return f"Command executed: {cmd}"

    def radar_data_receiver(self):
        """接收雷达主动上报数据的线程"""
        while self.active:
            try:
                if not self.radar_sock:
                    time.sleep(1)
                    continue

                # 接收雷达数据
                data = self.radar_sock.recv(2048)
                if not data:
                    print("[Radar] Radar disconnected")
                    self.radar_sock.close()
                    self.radar_sock = None
                    continue

                # 处理雷达数据
                current_time = datetime.now().strftime("%H:%M:%S.%f")[:-3]
                print(f"[Radar][{current_time}] Received data: {data.hex()}")

                # 转发到主服务器
                counter = self.get_next_counter()
                message = f"[RADAR_REPORT] {data.hex()} [CNT] {counter}"

                with self.lock:
                    if self.active and self.sock:
                        try:
                            self.sock.sendall(message.encode())
                            print(f"[Client][{current_time}] Forwarded radar data (Count: {counter})")
                        except (OSError, ConnectionError) as e:
                            print(f"[Client] Radar data forward error: {str(e)}")
                            self.reconnect_flag = True
                            break

            except socket.timeout:
                continue
            except Exception as e:
                print(f"[Radar] Receiver error: {str(e)}")
                if self.radar_sock:
                    self.radar_sock.close()
                    self.radar_sock = None
                time.sleep(1)

    def time_sender(self):
        """时间上报线程"""
        while self.active:
            try:
                now = datetime.now()
                current_minute = now.minute

                if current_minute != self.last_minute:
                    self.last_minute = current_minute

                    beijing_time = now.strftime("%Y-%m-%d %H:%M:%S")
                    counter = self.get_next_counter()
                    message = f"[TIME] {beijing_time} [CNT] {counter}"

                    with self.lock:
                        if self.active and self.sock:
                            try:
                                self.sock.sendall(message.encode())
                                current_time = now.strftime("%H:%M:%S.%f")[:-3]
                                print(f"[Client][{current_time}] Sent time report (Count: {counter})")
                            except (OSError, ConnectionError) as e:
                                print(f"[Client] Send error: {str(e)}")
                                self.reconnect_flag = True
                                break

                    next_minute = (now + timedelta(minutes=1)).replace(second=0, microsecond=0)
                    delay = (next_minute - now).total_seconds()
                    time.sleep(max(0, min(delay, 60)))
                else:
                    time.sleep(1)

            except Exception as e:
                print(f"[Client] Time sender error: {str(e)}")
                self.reconnect_flag = True
                break

    def plc_data_sender(self):
        """传感器数据上报线程"""
        while self.active:
            try:
                now = datetime.now()
                current_minute = now.minute

                if current_minute != self.last_plc_minute:
                    self.last_plc_minute = current_minute

                    # PLC数据上报
                    # plc_data = self.plc.active_escalation()
                    plc_data = self.plc.test()
                    counter = self.get_next_counter()
                    message = f"[PLC_REPORT] {plc_data} [CNT] {counter}"

                    with self.lock:
                        if self.active and self.sock:
                            try:
                                self.sock.sendall(message.encode())
                                current_time = now.strftime("%H:%M:%S.%f")[:-3]
                                print(f"[Client][{current_time}] Sent PLC report (Count: {counter})")
                            except (OSError, ConnectionError) as e:
                                print(f"[Client] PLC send error: {str(e)}")
                                self.reconnect_flag = True
                                break

                    # 同步等待
                    if current_minute == self.last_minute:
                        next_minute = (now + timedelta(minutes=1)).replace(second=0, microsecond=0)
                        delay = (next_minute - now).total_seconds()
                        time.sleep(max(0, min(delay, 60)))
                else:
                    time.sleep(1)

            except Exception as e:
                print(f"[Client] Sensor sender error: {str(e)}")
                self.reconnect_flag = True
                break
    def weather_data_sender(self):
        """传感器数据上报线程"""
        while self.active:
            try:
                now = datetime.now()
                current_minute = now.minute

                if current_minute != self.last_weather_minute:
                    self.last_weather_minute = current_minute

                    # 气象站数据上报
                    # weather_data = self.weather.active_escalation()
                    weather_data = self.weather.test()
                    counter = self.get_next_counter()
                    message = f"[WS_REPORT] {weather_data} [CNT] {counter}"

                    with self.lock:
                        if self.active and self.sock:
                            try:
                                self.sock.sendall(message.encode())
                                current_time = now.strftime("%H:%M:%S.%f")[:-3]
                                print(f"[Client][{current_time}] Sent Weather report (Count: {counter})")
                            except (OSError, ConnectionError) as e:
                                print(f"[Client] Weather send error: {str(e)}")
                                self.reconnect_flag = True
                                break

                    # 同步等待
                    if current_minute == self.last_minute:
                        next_minute = (now + timedelta(minutes=1)).replace(second=0, microsecond=0)
                        delay = (next_minute - now).total_seconds()
                        time.sleep(max(0, min(delay, 60)))
                else:
                    time.sleep(1)

            except Exception as e:
                print(f"[Client] Sensor sender error: {str(e)}")
                self.reconnect_flag = True
                break

    def run(self):
        """主运行循环"""
        while True:
            self.reconnect_flag = False
            try:
                # 连接主服务器
                with socket.create_connection((HOST, PORT), timeout=30) as sock:
                    self.sock = sock
                    self.active = True
                    self.last_minute = datetime.now().minute
                    self.last_time_minute  = self.last_minute
                    self.last_plc_minute = self.last_minute
                    self.last_weather_minute = self.last_minute
                    self.last_radar_minute = self.last_minute

                    print("[Client] Connected to main server!")

                    # 连接雷达
                    # if self.connect_to_radar():
                    #     # 启动雷达得TCP线程
                    #     threading.Thread(target=self.radar_data_receiver, daemon=True).start()

                    # 启动其他线程
                    threading.Thread(target=self.time_sender, daemon=True).start()
                    threading.Thread(target=self.plc_data_sender, daemon=True).start()
                    threading.Thread(target=self.weather_data_sender, daemon=True).start()



                    # 主命令循环
                    while self.active:
                        try:
                            sock.settimeout(5)
                            data = sock.recv(1024)
                            if not data:
                                print("[Client] Server closed connection")
                                break

                            cmd = data.decode()
                            current_time = datetime.now().strftime("%H:%M:%S.%f")[:-3]
                            print(f"[Client][{current_time}] Received command: {cmd}")



                            feedback = self.process_command(cmd)
                            counter = self.get_next_counter()
                            full_feedback = f"{feedback} [CNT] {counter}"

                            with self.lock:
                                if self.active:
                                    sock.sendall(full_feedback.encode())
                                    current_time = datetime.now().strftime("%H:%M:%S.%f")[:-3]
                                    print(f"[Client][{current_time}] Sent feedback (Count: {counter})")

                        except socket.timeout:
                            continue
                        except (ConnectionResetError, BrokenPipeError) as e:
                            print(f"[Client] Connection error: {str(e)}")
                            self.reconnect_flag = True
                            break
                        except Exception as e:
                            print(f"[Client] Unexpected error: {str(e)}")
                            self.reconnect_flag = True
                            break

            except socket.timeout:
                print("[Client] Connection timeout, retrying...")
            except ConnectionRefusedError:
                print("[Client] Server unavailable, retrying...")
            except Exception as e:
                print(f"[Client] Connection failed: {str(e)}")

            # 清理资源
            self.active = False
            if self.sock:
                try:
                    self.sock.close()
                except:
                    pass
                self.sock = None

            if self.radar_sock:
                try:
                    self.radar_sock.close()
                except:
                    pass
                self.radar_sock = None

            if self.reconnect_flag:
                print("[Client] Reconnecting...")
                time.sleep(1)



if __name__ == "__main__":
    client = ClientConnection()
    client.run()